package com.atguigu.tingshu.payment.service.impl;

import cn.hutool.core.util.IdUtil;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.payment.PaymentInfo;
import com.atguigu.tingshu.payment.config.WxPayV3Config;
import com.atguigu.tingshu.payment.service.PaymentInfoService;
import com.atguigu.tingshu.payment.service.WxPayService;
import com.atguigu.tingshu.payment.util.PayUtil;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import io.seata.spring.annotation.GlobalTransactional;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {

    @Autowired
    private PaymentInfoService paymentInfoService;

    @Autowired
    private RSAAutoCertificateConfig rsaAutoCertificateConfig;

    @Autowired
    private WxPayV3Config wxPayV3Config;

    /**
     * 获取微信小程序拉起本地微信支付所需要参数
     *
     * @param paymentType 支付类型：支付类型：1301-订单 1302-充值
     * @param orderNo     订单编号
     * @return 小程序拉调用wx.requestPayment(Object object)需要参数
     */
    @Override
    public Map<String, Object> getWxPrePayParams(String paymentType, String orderNo) {
        Long userId = AuthContextHolder.getUserId();
        //1.将本次交易记录保存到本地交易表
        PaymentInfo paymentInfo = paymentInfoService.savePaymentInfo(paymentType, orderNo, userId);

        //2.调用微信SDK获取小程序支付所需参数
        //2.1 构建调用微信接口业务对象
        JsapiServiceExtension jsapiService = new JsapiServiceExtension.Builder().config(rsaAutoCertificateConfig).build();
        //2.2 构建预支付请求对象
        PrepayRequest prepayRequest = new PrepayRequest();
        Amount amount = new Amount();
        //2.2.1 设置预支付订单金额 单位：分 TODO开发接口暂时硬编码1分 实际应该从paymentInfo对象中获取
        amount.setTotal(1);
        prepayRequest.setAmount(amount);
        prepayRequest.setAppid(wxPayV3Config.getAppid());
        prepayRequest.setMchid(wxPayV3Config.getMerchantId());
        prepayRequest.setDescription(paymentInfo.getContent());
        //设置微信异步回调地址：用户支付成功后微信支付会异步通知商户系统告知：支付结果
        prepayRequest.setNotifyUrl(wxPayV3Config.getNotifyUrl());
        //2.3 TODO 目前小程序未发布，开发阶段必选设置付款人（真正付款只有应用开发者列表中微信账户才有权限）
        Payer payer = new Payer();
        payer.setOpenid("odo3j4qp-wC3HVq9Z_D9C0cOr0Zs");//TODO能拉起微信支付，但是付款会报错：当前用户不是开发者
        prepayRequest.setPayer(payer);
        //2.2.2 商户端订单编号
        prepayRequest.setOutTradeNo(paymentInfo.getOrderNo());
        //2.3 调用下单方法（小程序所需参数），得到应答
        PrepayWithRequestPaymentResponse response = jsapiService.prepayWithRequestPayment(prepayRequest);
        if (response != null) {
            Map<String, Object> mapResult = new HashMap<>();
            mapResult.put("timeStamp", response.getTimeStamp());
            mapResult.put("package", response.getPackageVal());
            mapResult.put("paySign", response.getPaySign());
            mapResult.put("signType", response.getSignType());
            mapResult.put("nonceStr", response.getNonceStr());
            return mapResult;
        }
        return null;
    }

    /**
     * 根据商户订单编号查询交易状态
     *
     * @param orderNo
     * @return
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public Boolean queryPayStatus(String orderNo) {
        //1.创建查询交易请求对象
        //QueryOrderByOutTradeNoRequest queryOrderByOutTradeNoRequest = new QueryOrderByOutTradeNoRequest();
        //queryOrderByOutTradeNoRequest.setMchid(wxPayV3Config.getMerchantId());
        //queryOrderByOutTradeNoRequest.setOutTradeNo(orderNo);
        //
        ////2.创建调用微信服务端业务对象
        //JsapiServiceExtension jsapiService = new JsapiServiceExtension.Builder().config(rsaAutoCertificateConfig).build();
        //
        ////3.调用微信查询交易状态接口
        //Transaction transaction = jsapiService.queryOrderByOutTradeNo(queryOrderByOutTradeNoRequest);
        //
        ////4.解析响应结果返回交易状态
        //if (transaction != null) {
        //    Transaction.TradeStateEnum tradeState = transaction.getTradeState();
        //    if (Transaction.TradeStateEnum.SUCCESS == tradeState) {
        //        //用户支付成功
        //        return true;
        //    }
        //}
        //return false;

        //1.修改本地交易记录状态
        Transaction transaction = new Transaction();
        transaction.setOutTradeNo(orderNo);
        transaction.setTransactionId("WX"+ IdUtil.getSnowflakeNextId());
        paymentInfoService.updatePaymentInfoSuccess(transaction);
        return true;
    }


    /**
     * 用户付款成功后，处理微信支付异步回调
     *
     * @param request
     * @return
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public Map<String, String> paySuccessNotify(HttpServletRequest request) {
        //1.从请求头中获取微信提交参数
        String wechatPaySerial = request.getHeader("Wechatpay-Serial");  //签名
        String nonce = request.getHeader("Wechatpay-Nonce");  //签名中的随机数
        String timestamp = request.getHeader("Wechatpay-Timestamp"); //时间戳
        String signature = request.getHeader("Wechatpay-Signature"); //签名类型

        //HTTP 请求体 body。切记使用原始报文，不要用 JSON 对象序列化后的字符串，避免验签的 body 和原文不一致。
        String requestBody = PayUtil.readData(request);
        //2.构建RequestParam请求参数对象
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(wechatPaySerial)
                .nonce(nonce)
                .signature(signature)
                .timestamp(timestamp)
                .body(requestBody)
                .build();
        //3.// 初始化 NotificationParser 解析器对象
        NotificationParser parser = new NotificationParser(rsaAutoCertificateConfig);
        //4. 调用解析器对象解析方法 验签、解密 并转换成 Transaction
        Transaction transaction = parser.parse(requestParam, Transaction.class);
        if (transaction != null) {
            //4.1 业务验证，验证付款状态以及用户实际付款金额跟商户侧金额是否一致
            if (Transaction.TradeStateEnum.SUCCESS == transaction.getTradeState()) {
                Integer payerTotal = transaction.getAmount().getPayerTotal();
                //todo 调试阶段支付金额为1分，后续改为动态从本地交易记录中获取实际金额
                if (payerTotal.intValue() == 1) {
                    //4.2 更新本地交易记录状态
                    paymentInfoService.updatePaymentInfoSuccess(transaction);
                    Map<String, String> map = new HashMap<>();
                    map.put("code", "SUCCESS");
                    map.put("message", "SUCCESS");
                    return map;
                }
            }
        }
        return null;
    }
}
